package com.spring.zabelection.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.spring.zabelection.websocket.WebSocketServer;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.*;

/**
 * @program: awesome-spring
 * @description: leader选举逻辑类
 * @author: Alex Wu
 * @createDate: 2025-04-01 10:44
 **/
@Service
public class LeaderElectionService {

    @Autowired
    private  WebSocketServer webSocketServer;
    private final ObjectMapper objectMapper = new ObjectMapper();
    private final int serverId = new Random().nextInt(100);  // 随机 server_id
    private long zxid = new Random().nextInt(100); // 初始 ZXID
    private boolean isLeader = false;
    private final Map<Integer, List<Long>> votes = new HashMap<>();

    @Value("${vote.count}")
    private Integer voteCount;



    @PostConstruct
    public void init() {
        // 选举不立即开始，而是等到收到投票请求后触发
        System.out.println("🕒 服务器 " + serverId + " 启动，等待投票...");
        // 初次将自己的投票信息加入到投票列表中
        votes.computeIfAbsent(serverId, k -> new ArrayList<>()).add(zxid);
    }



    /**
     * 处理接收到的投票信息，并根据 ZXID 进行 Leader 选举。
     *
     * @param senderId 发送投票的服务器 ID
     * @param senderZxid 发送投票服务器的 ZXID（事务 ID）
     * @throws Exception 可能的异常
     */
    public void receiveVote(int senderId, long senderZxid) throws Exception {
        System.out.println("📩 收到来自服务器 " + senderId + " 的投票，ZXID: " + senderZxid);

        // 记录当前服务器收到的投票信息
        votes.computeIfAbsent(senderId, k -> new ArrayList<>()).add(senderZxid);


        int needVoteCount = voteCount / 2 + 1;

        // 必须超过半数的投票才能进行选举
        if (votes.size() < needVoteCount) {
            return;
        }


        // 选择当前服务器作为默认的最佳候选 Leader
        int bestServer = serverId;
        long maxZxid = zxid;


        for (var entry : votes.entrySet()) {
            // 如果是自己的选票,则跳过
            if (entry.getKey() == serverId) {
                continue;
            }
            for (long zxid : entry.getValue()) {
                if (zxid > maxZxid || (zxid == maxZxid && entry.getKey() > bestServer)) {
                    maxZxid = zxid;
                    bestServer = entry.getKey();
                }
            }
        }


       /* // 遍历所有收到的投票，选出 ZXID 最大的服务器
        for (var entry : votes.entrySet()) {
            // 如果是自己的选票,则跳过
            if (entry.getKey() == serverId && entry.getValue().equals(zxid)) {
                continue;
            }

            // 规则：
            // 1. 如果投票的 ZXID 比当前最大 ZXID 大，则更新
            // 2. 如果 ZXID 相同，选择服务器 ID 更大的作为 Leader
            if (entry.getValue() > maxZxid || (entry.getValue() == maxZxid && entry.getKey() > bestServer)) {
                maxZxid = entry.getValue();
                bestServer = entry.getKey();
            }
        }*/

        // 统计投给最大 ZXID 的服务器的票数
        long finalMaxZxid = maxZxid;
        long count = votes.values().stream()
                .flatMap(List::stream)  // 扁平化 List
                .filter(v -> v == finalMaxZxid)
                .count();

        // 规则：如果某个 ZXID 获得的票数超过半数（Quorum），则选举成功
        System.out.println("📈 统计到 ZXID " + maxZxid + " 的投票数：" + count);
        if (count >= (votes.size() / 2 + 1)) {
            // 多数节点投票后，判断当前服务器是否是 Leader
            isLeader = bestServer == serverId;
            System.out.println(isLeader ? "🏆 我是 Leader" : "📌 我是 Follower");
            // TODO 结果告知其他服务器
        }else {
            System.out.println("📈 统计到 ZXID " + maxZxid + " 的投票数：" + count + "，未超过半数，选举失败");
            // 继续广播投票，推动选举进行
            broadcastVote(bestServer, maxZxid);
        }
    }

    /**
     * 广播当前服务器的投票信息
     */
    private void broadcastVote(int leaderId, long leaderZxid) throws Exception {
        String message = objectMapper.writeValueAsString(Map.of(
                "serverId", leaderId,  // 这里应该是当前认为的 Leader ID
                "zxid", leaderZxid,     // 这里应该是当前认为的最高 ZXID
                "type", "重发的信息"
        ));
        webSocketServer.broadcastMessage(message);
    }

    public Integer getServerId() {
        return serverId;
    }

    public Long getZxid() {
        return zxid;
    }
}
